package org.geom;

public class Vector3D {

	public float x = 0;
	public float y = 0;
	public float z = 0;
	
	public Vector3D() {}
	public Vector3D(float x, float y, float z) {
		this.x = x;
		this.y = y;
		this.z = z;
	}
	
	public Vector3D(double x, double y, double z) {
		this.x = (float) x;
		this.y = (float) y;
		this.z = (float) z;
	}
	
	public String toString() {
		return x+" - "+y+" - "+z;
	}
	
	public boolean equals(Vector3D n) {
		if(n==null) return false;
		
		if(x==n.x && y==n.y && z==n.z) return true;
		else return false;
	}
	
	public Vector3D duplicate() {
		Vector3D p = new Vector3D();
		p.x = x;
		p.y = y;
		p.z = z;
		
		return p;
	}
	
	public Vector3D minus(Vector3D n) {
		return new Vector3D(this.x-n.x, 
				this.y-n.y,
				this.z-n.z);
	}
	
	public final float dot(Vector3D v) {
		return x * v.x + y * v.y + z * v.z;
	}

	public float mag() {
		return (float) Math.sqrt(x*x + y*y + z*z);
	}
	
	public void normalized() {
		float mag = (float) Math.sqrt(x*x + y*y + z*z);

		if (mag > 0) {
			mag = 1f / mag;
			x *= mag;
			y *= mag;
			z *= mag;
		} 
	}

	public final Vector3D crossSelf(Vector3D v) {
        final float cx = y * v.z - v.y * z;
        final float cy = z * v.x - v.z * x;
        z = x * v.y - v.x * y;
        y = cy;
        x = cx;
        return this;
}

	public Vector3D cross(Vector3D m) {
		return Vector3D.crossProduct(this, m);
	}
	
	public static Vector3D crossProduct(Vector3D n, Vector3D m) {
		/*
		 * a * b * sin(theta)
		 * theta = angle between two vectors
		 * 
		 * */
		Vector3D ret = new Vector3D();
		
		/*float theta = (float)Math.acos(a.dot(b));
		float sinTheta = Maths.sin(theta);

		ret.x = a.x * b.x * sinTheta;
		ret.y = a.y * b.y * sinTheta;
		ret.z = a.z * b.z * sinTheta;*/

		ret.x = n.y * m.z - m.y * n.z;

		ret.y = n.z * m.x - m.z * n.x;

		ret.z = n.x * m.y - n.y * m.x;

		//return ret;

		return ret;

	}

	public final Vector3D rotateAroundAxis(Vector3D axis, float theta) {
		final float ux = axis.x * x;
		final float uy = axis.x * y;
		final float uz = axis.x * z;
		final float vx = axis.y * x;
		final float vy = axis.y * y;
		final float vz = axis.y * z;
		final float wx = axis.z * x;
		final float wy = axis.z * y;
		final float wz = axis.z * z;
		final double si = Math.sin(theta);
		final double co = Math.cos(theta);
		float xx = (float) (axis.x
				* (ux + vy + wz)
				+ (x * (axis.y * axis.y + axis.z * axis.z) - axis.x * (vy + wz))
				* co + (-wy + vz) * si);
		float yy = (float) (axis.y
				* (ux + vy + wz)
				+ (y * (axis.x * axis.x + axis.z * axis.z) - axis.y * (ux + wz))
				* co + (wx - uz) * si);
		float zz = (float) (axis.z
				* (ux + vy + wz)
				+ (z * (axis.x * axis.x + axis.y * axis.y) - axis.z * (ux + vy))
				* co + (-vx + uy) * si);
		x = xx;
		y = yy;
		z = zz;
		return this;
	}
	
	public static Vector3D getTangentBetweenTwoPoint(Vector3D p1, Vector3D p2) {

		Vector3D r = new Vector3D( 
				p1.x-p2.x,
				p1.y-p2.y,
				p1.z-p2.z);
		r.normalized();
		return r;
	}
	
}
